跳到主要内容

Docker 打包 Go 应用

简单的打包 Golang 应用

docker pull golang:1.17

在项目根目录创建 Dockerfile 文件,写入内容

FROM golang:1.17

ENV GOPROXY https://goproxy.cn,direct
# 设置工作目录(或者称为当前目录)如果目录不存在,WORKDIR 会帮你建立目录
WORKDIR $GOPATH/src/github.com/example/go-gin-example
# 把当前目录的文件移动到镜像里面来
COPY . $GOPATH/src/github.com/example/go-gin-example
RUN go build .

EXPOSE 8000

# 容器启动程序设置为 ./go-gin-example
ENTRYPOINT ["./go-gin-example"]

一般项目会连接 MySQL,那这里如何动态的连接上 MySQL 呢?

修改配置文件(看自己项目,总之就是修改一个 HOST 地址)

[database]
TYPE = mysql
USER = root
PASSWORD = rootroot
HOST = mysql:3306
NAME = blog
TABLE_PREFIX = blog_

然后再在当前目录下构建镜像

docker build -t gin-blog-docker .

这里 -t 指定名称为 gin-blog-docker,. 构建内容为当前上下文目录

检查镜像是否存在

docker images

拉取一个 MySQL 镜像下来

docker pull mysql:5.7

运行 Mysql 容器,并设置执行成功后返回容器 ID

docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=rootroot -v ./data:/var/lib/mysql -d mysql:5.7

运行自己打包的镜像

docker run --link mysql:mysql -p 8000:8000 gin-blog-docker

增加命令 --link mysql:mysql 让 Golang 容器与 Mysql 容器互联;通过 --link,可以在容器内直接使用其关联的容器别名进行访问,而不通过 IP,但是 --link 只能解决单机容器间的关联,在分布式多机的情况下,需要通过别的方式进行连接

Docker 容器的 IP 地址是不固定的,容器重启后地址可能就和之前不同了。link 操作除了在将 link 信息保存在接收容器之外,还在 /etc/hosts 中添加了一项---源窗口的 IP 和别名 (--link 参数指定的别名),以用来解析源容器的 IP 地址。并且当源容器重启后,会自动更新接收器的 /etc/hosts 文件。因此可以用这个别名来配置应用程序,而不有和担心 IP 的变化。

打包一个精简版镜像

打包后可以发现镜像的体积巨大

可以发现主要是依赖的这个 Golang 镜像也巨大

官方 golang 镜像,包含 Golang 的编译和运行环境,外加一堆 GCC、build 工具,相当齐全

这是有问题的,我们可以不在 Golang 容器中现场编译的,压根用不到那些东西,我们只需要一个能够运行可执行文件的环境即可

可以使用 Scratch 镜像,简洁、小巧,基本是个空镜像

FROM scratch

WORKDIR $GOPATH/src/github.com/example/go-gin-example
COPY . $GOPATH/src/github.com/example/go-gin-example

EXPOSE 8000
CMD ["./go-gin-example"]

编译可执行文件,这里使用交叉编译

CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o go-gin-example .

编译所生成的可执行文件会依赖一些库,并且是动态链接。在这里因为使用的是 scratch 镜像,它是空镜像,因此我们需要将生成的可执行文件静态链接所依赖的库

再次构建

docker build -t gin-blog-docker-scratch .

可以看到打包出来的镜像才 38M

运行测试

docker run --link mysql:mysql -p 8000:8000 gin-blog-docker-scratch

执行成功